package com.cefa.finance.task;

import com.alibaba.fastjson.JSON;
import com.cefa.finance.config.ConstantProperties;
import com.cefa.finance.dao.*;
import com.cefa.finance.model.*;
import com.cefa.finance.service.BlockChainService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.Date;
import java.util.List;

import sun.misc.BASE64Encoder;

@SuppressWarnings("ALL")
@Service
public class BlockChainTask {

    private static final Logger logger = LoggerFactory.getLogger(BlockChainTask.class);

    @Autowired
    private BlockChainService blockChainService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private VehicleRepository vehicleRepository;

    @Autowired
    private MaintenanceRecordRepository maintenanceRecordRepository;

    @Autowired
    private AccidentRecordRepository accidentRecordRepository;

    @Autowired
    private RepaymentRecordRepository repaymentRecordRepository;

    @Autowired
    private ContractRepository contractRepository;

    @Autowired
    private FileContractBlockDataRepository fileContractBlockDataRepository;

    @Autowired
    private ConstantProperties constantProperties;

    @Scheduled(cron = "0 0/1 * * * ? ")
    public void putUserInfoOnBlockChain() {
        try {
            List<User> users = userRepository.findUnBlockedUsers();
            if (users.size() != 0) {
                for (User user : users) {
                    Account recordUser = accountRepository.findOne(user.getRecordUser());
                    if (user.getUserFileAddress() == null) {
                        try {
                            String userFileAddress = blockChainService.getFileAddress(user.getRecordUser());
                            if (userFileAddress != null) {
                                user.setUserFileAddress(userFileAddress);
                                User blockUser = userRepository.save(user);
                                String idCode = blockUser.getIdCode();
                                blockUser.setIdCode(null);
                                String stableJson = blockChainService.tostableJSON(JSON.toJSONString(blockUser));
                                if (stableJson != null) {
                                    User jsonUser = blockChainService.putUserInfoOnBlockchain(recordUser.getPrikey(), userFileAddress, stableJson);
                                    blockUser.setBlockHash(jsonUser.getBlockHash());
                                    blockUser.setBlockNumber(jsonUser.getBlockNumber());
                                    blockUser.setBlockStatus(true);
                                    blockUser.setIdCode(idCode);
                                    userRepository.save(blockUser);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            String idCode = user.getIdCode();
                            user.setIdCode(null);
                            String stableJson = blockChainService.tostableJSON(JSON.toJSONString(user));
                            if (stableJson != null) {
                                User jsonUser = blockChainService.putUserInfoOnBlockchain(recordUser.getPrikey(), user.getUserFileAddress(), stableJson);
                                if (jsonUser != null) {
                                    user.setBlockHash(jsonUser.getBlockHash());
                                    user.setBlockNumber(jsonUser.getBlockNumber());
                                    user.setBlockStatus(true);
                                    user.setIdCode(idCode);
                                    userRepository.save(user);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Scheduled(cron = "0 0/1 * * * ? ")
    public void putVehicleInfoOnBlockChain() {

        try {
            List<Vehicle> vehicles = vehicleRepository.findUnBlockedVehicles();
            if (vehicles.size() != 0) {
                for (Vehicle vehicle : vehicles) {
                    Account recordUser = accountRepository.findOne(vehicle.getRecordUser());
                    if (vehicle.getVehicleFileAddress() == null) {
                        try {
                            String vehicleFileAddress = blockChainService.getFileAddress(vehicle.getRecordUser());
                            if (vehicleFileAddress != null) {
                                vehicle.setVehicleFileAddress(vehicleFileAddress);
                                Vehicle blockVehicle = vehicleRepository.save(vehicle);
                                String stableJson = blockChainService.tostableJSON(JSON.toJSONString(blockVehicle));
                                if (stableJson != null) {
                                    Vehicle jsonVehicle = blockChainService.putVehicleInfoOnBlockchain(recordUser.getPrikey(), vehicleFileAddress, stableJson);
                                    if (jsonVehicle != null) {
                                        blockVehicle.setBlockHash(jsonVehicle.getBlockHash());
                                        blockVehicle.setBlockStatus(true);
                                        blockVehicle.setBlockNumber(jsonVehicle.getBlockNumber());
                                        vehicleRepository.save(blockVehicle);
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            String stableJson = blockChainService.tostableJSON(JSON.toJSONString(vehicle));
                            if (stableJson != null) {
                                Vehicle jsonVehicle = blockChainService.putVehicleInfoOnBlockchain(recordUser.getPrikey(), vehicle.getVehicleFileAddress(), stableJson);
                                if (jsonVehicle != null) {
                                    vehicle.setBlockNumber(jsonVehicle.getBlockNumber());
                                    vehicle.setBlockStatus(true);
                                    vehicle.setBlockHash(jsonVehicle.getBlockHash());
                                    vehicleRepository.save(vehicle);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Scheduled(cron = "0 0/1 * * * ? ")
    public void putMaintenInfoOnBlockChain() {

        List<MaintenanceRecord> maintenanceRecords = maintenanceRecordRepository.findUnBlockedMaintenanceRecord();

        if (maintenanceRecords.size() != 0) {
            for (MaintenanceRecord maintenanceRecord : maintenanceRecords) {
                try {
                    Account recordUser = accountRepository.findOne(maintenanceRecord.getRecordUser());
                    Vehicle vehicle = vehicleRepository.findOne(maintenanceRecord.getVehicleId());

                    if (vehicle.getVehicleFileAddress() != null) {
                        String stableJson = blockChainService.tostableJSON(JSON.toJSONString(maintenanceRecord));
                        if (stableJson != null) {
                            Vehicle jsonVehicle = blockChainService.putVehicleInfoOnBlockchain(recordUser.getPrikey(), vehicle.getVehicleFileAddress(), stableJson);
                            if (jsonVehicle != null) {
                                maintenanceRecord.setBlockNumber(jsonVehicle.getBlockNumber());
                                maintenanceRecord.setBlockHash(jsonVehicle.getBlockHash());
                                maintenanceRecord.setBlockStatus(true);
                                MaintenanceRecord save = maintenanceRecordRepository.save(maintenanceRecord);
                                logger.info("车辆保养信息上链-------------" + JSON.toJSONString(save));
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Scheduled(cron = "0 0/1 * * * ? ")
    public void putAccidentInfoOnBlockChain() {

        List<AccidentRecord> accidentRecords = accidentRecordRepository.findUnBlockedAccidentRecord();

        if (accidentRecords.size() != 0) {
            for (AccidentRecord accidentRecord : accidentRecords) {
                try {
                    Account recordUser = accountRepository.findOne(accidentRecord.getRecordUser());
                    Vehicle vehicle = vehicleRepository.findOne(accidentRecord.getVehicleId());

                    if (vehicle.getVehicleFileAddress() != null) {
                        String stableJson = blockChainService.tostableJSON(JSON.toJSONString(accidentRecord));
                        if (stableJson != null) {
                            Vehicle jsonVehicle = blockChainService.putVehicleInfoOnBlockchain(recordUser.getPrikey(), vehicle.getVehicleFileAddress(), stableJson);
                            if (jsonVehicle != null) {
                                accidentRecord.setBlockNumber(jsonVehicle.getBlockNumber());
                                accidentRecord.setBlockHash(jsonVehicle.getBlockHash());
                                accidentRecord.setBlockStatus(true);
                                AccidentRecord save = accidentRecordRepository.save(accidentRecord);
                                logger.info("车辆保养信息上链-------------" + JSON.toJSONString(save));
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Scheduled(cron = "0 0/1 * * * ? ")
    public void putRepaymentInfoOnBlockChain() {

        List<RepaymentRecord> repaymentRecords = repaymentRecordRepository.findUnBlockedRepaymentRecord();

        if (repaymentRecords.size() != 0) {
            for (RepaymentRecord repaymentRecord : repaymentRecords) {
                try {
                    Account recordUser = accountRepository.findOne(repaymentRecord.getRecordUser());
                    User user = userRepository.findOne(repaymentRecord.getUserId());

                    if (user.getUserFileAddress() != null) {
                        String stableJson = blockChainService.tostableJSON(JSON.toJSONString(repaymentRecord));
                        if (stableJson != null) {
                            User jsonUser = blockChainService.putUserInfoOnBlockchain(recordUser.getPrikey(), user.getUserFileAddress(), stableJson);
                            if (jsonUser != null) {
                                repaymentRecord.setBlockNumber(jsonUser.getBlockNumber());
                                repaymentRecord.setBlockHash(jsonUser.getBlockHash());
                                repaymentRecord.setBlockStatus(true);
                                RepaymentRecord save = repaymentRecordRepository.save(repaymentRecord);
                                logger.info("用户还款信息上链-------------" + JSON.toJSONString(save));
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Scheduled(cron = "0 0/1 * * * ? ")
    public void putContractInfoOnBlockChain() {
        try {
            List<Contract> contracts = contractRepository.findUnBlockedContracts();

            if (contracts.size() != 0) {
                for (Contract contract : contracts) {
                    List<FileContractBlockData> fileContracts = fileContractBlockDataRepository.findByContractId(contract.getId());
                    if (fileContracts.size() > 0) {
                        fileContractBlockDataRepository.delete(fileContracts);
                    }

                    String originContractName = contract.getOriginContractName();
                    if (originContractName != null) {
                        String[] split = originContractName.split(",");
                        for (String fileName : split) {
                            FileContractBlockData newInfo = new FileContractBlockData();
                            newInfo.setOriginContractName(fileName);
                            String contractName = contract.getUserId() + "_" + contract.getVehicleId() + "_" + contract.getId() + "_" + fileName;
                            newInfo.setContractName(contractName);
                            newInfo.setContractId(contract.getId());
                            newInfo.setVehicleId(contract.getVehicleId());
                            newInfo.setUserId(contract.getUserId());
                            fileContractBlockDataRepository.save(newInfo);
                        }
                    }

                    List<FileContractBlockData> fileNew = fileContractBlockDataRepository.findByContractId(contract.getId());
                    User user = userRepository.findOne(contract.getUserId());
                    Account recordUser = accountRepository.findOne(contract.getRecordUser());

                    if (fileNew.size() > 0) {
                        for (FileContractBlockData file : fileNew) {
                            String fileString = getBase64String(file.getContractName());
                            if (fileString != null) {
                                try {
                                    String hashFile = blockChainService.ToSha3(fileString);
                                    if (hashFile != null) {
                                        FileContractBlockData fileBlock = blockChainService.uploadContractOnBlockchain(recordUser.getPrikey(), user.getUserFileAddress(), hashFile);
                                        if (fileBlock != null) {
                                            file.setBlockRegTime(new Date());
                                            file.setBlockHash(fileBlock.getBlockHash());
                                            file.setBlockNumber(fileBlock.getBlockNumber());
                                            file.setTransactionHash(fileBlock.getTransactionHash());
                                            file.setBlockStatus(true);
                                            file.setSha3data(hashFile);
                                            fileContractBlockDataRepository.save(file);
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }

                    List<FileContractBlockData> notOnBlock = fileContractBlockDataRepository.findByBlockStatus(contract.getId());
                    if (notOnBlock.size() == 0) {
                        contract.setBlockStatus(true);
                        contractRepository.save(contract);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Scheduled(cron = "0 0/1 * * * ? ")
    public void getUserPrivateKeyTask() {

        logger.info("---------------获取用户私钥---------------");

        List<Account> noPrivateKeyAccount = accountRepository.findNoPrivateKeyAccount();

        if (noPrivateKeyAccount.size() > 0) {
            for (Account account : noPrivateKeyAccount) {
                try {
                    Account wallet = null;
                    try {
                        wallet = blockChainService.getWallet();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (wallet != null && wallet.getPrikey() != null && wallet.getAddress() != null) {
                        account.setPrikey(wallet.getPrikey());
                        account.setAddress(wallet.getAddress());
                        accountRepository.save(account);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private String getFileHash(String fileName) {
        String filePath = constantProperties.contractPath;
        File file = new File(filePath, fileName);
        StringBuilder stringBuilder = null;
        if (file.exists()) {
            FileReader reader = null;
            BufferedReader bufferedReader = null;
            try {
                reader = new FileReader(file);
                bufferedReader = new BufferedReader(reader);
                stringBuilder = new StringBuilder();
                String s = "";
                while ((s = bufferedReader.readLine()) != null) {
                    stringBuilder.append(s);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (reader != null) {
                        reader.close();
                    }
                    if (bufferedReader != null) {
                        bufferedReader.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (stringBuilder != null && stringBuilder.length() > 0) {
                return stringBuilder.toString();
            }
        }
        return null;
    }


    private String getBase64String(String fileName) {
        String filePath = constantProperties.contractPath;
        File file = new File(filePath, fileName);
        byte[] data = null;
        if (file.exists()) {
            InputStream in = null;
            try {
                in = new FileInputStream(file);
                data = new byte[in.available()];
                int read = in.read(data);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (data != null && data.length > 0) {
                BASE64Encoder encoder = new BASE64Encoder();
                return encoder.encode(data);
            }
        }
        return null;
    }
}